package application.util;

import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.MethodParameterScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ConfigurationBuilder;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * 反射的工具类
 */
public class ReflectionsUtil {

    private static Reflections reflections;

    /**
     * 初始化反射工具，它在程序启动时，已经在Program类的子类中被调用过，一般情况下，只要@ScannerPackage注解中的包名是正确的，不需要开发者手动调用此方法。
     *
     * @param packageName 被反射工具扫描的最顶层的包名
     * @return 反射工具对象实例。
     */
    public static synchronized Reflections init(String packageName) {
        if (reflections != null) {
            return reflections;
        }
        reflections = new Reflections(new ConfigurationBuilder().forPackages(packageName)
                .addScanners(new SubTypesScanner())
                .addScanners(new FieldAnnotationsScanner())
                .addScanners(new MethodAnnotationsScanner())
                .addScanners(new MethodParameterScanner()));
        return reflections;
    }

    /**
     * 获取拥有指定注解的类的Class对象
     *
     * @param cls 指定的注解的Class对象
     *            注意此注解不能被子类继承
     * @return 拥有cls注解的所有类的类对象的Set集合
     */
    public static Set<Class<?>> getAnnotationByClass(Class<? extends Annotation> cls) {
        Set<Class<?>> annotatedWith = reflections.getTypesAnnotatedWith(cls, true);
        return annotatedWith;
    }

    /**
     * 返回拥有指定注解的类的Class对象
     *
     * @param cls            指定注解的Class对象
     *                       注意：
     *                       若honorInherited变量为true，则注解不能被子类继承
     *                       若honorInherited变量为false，则注解可以被子类继承
     * @param honorInherited 此变量表示子类是否拥有cls注解 true时表示，子类不拥有cls注解，为false时反之
     * @return 拥有cls注解的类的类对象的Set集合
     */
    public static Set<Class<?>> getAnnotationByClass(Class<? extends Annotation> cls, boolean honorInherited) {
        Set<Class<?>> annotatedWith = reflections.getTypesAnnotatedWith(cls, honorInherited);
        return annotatedWith;
    }

    /**
     * 返回拥有指定注解的成员变量的Field变量的Set集合
     *
     * @param cls 指定注解的Class对象
     * @return 返回拥有cls注解的所有成员变量的Set集合
     */
    public static Set<Field> getAnnotationByField(Class<? extends Annotation> cls) {
        Set<Field> fields = reflections.getFieldsAnnotatedWith(cls);
        return fields;
    }

    /**
     * 获取拥有指定注解的Method对象的Set集合
     *
     * @param cls 指定注解的Class对象
     * @return 拥有cls注解的Method的Set集合
     */
    public static Set<Method> getAnnotationByMethod(Class<? extends Annotation> cls) {
        Set<Method> methods = reflections.getMethodsAnnotatedWith(cls);
        return methods;
    }
}
